package com.dianban.controller.nengliang;

import com.dianban.base.ResultCode;
import com.dianban.base.ResultVo;
import com.dianban.config.redis.RedisConstant;
import com.dianban.config.redis.RedisUtil;
import com.dianban.controller.BaseController;
import com.dianban.entity.FacePayConfig;
import com.dianban.entity.JwUserAccount;
import com.dianban.entity.User;
import com.dianban.service.FacePayConfigService;
import com.dianban.service.JwUserAccountService;
import com.dianban.utils.TencentRealnameAuthUtils;
import com.dianban.utils.UserUtils;
import com.tencentcloudapi.ocr.v20181119.models.BankCardOCRResponse;
import com.tencentcloudapi.ocr.v20181119.models.IDCardOCRResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;

@Api(value = "ApiUserAccountController", description = "用户实名信息控制器")
@RestController
@RequestMapping(value = "${interfacePath}/nengliang/account/")
public class ApiUserAccountController extends BaseController {

    @Value("${rongyaotuadmin.domain}")
    private String rongyaotuadminDomain;

    @Autowired
    private FacePayConfigService facePayConfigService;
    @Autowired
    private JwUserAccountService jwUserAccountService;

    @ApiOperation(notes = "info", httpMethod = "GET", value = "用户实名信息详情")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userToken", value = "用户token", required = true, paramType = "header", dataType = "string"),
    })
    @RequestMapping(value = "info", method = RequestMethod.GET)
    public ResultVo info(HttpServletRequest request, HttpServletResponse response) {
        String userToken = request.getHeader(UserUtils.USER_TOKEN);
        String key = RedisConstant.USER_TOKEN_KEY + userToken;
        User user = (User) RedisUtil.get(key);
        if (user == null) {
            return ResultVo.error(ResultCode.ERROR, "请求头userToken过期");
        }
        JwUserAccount jwUserAccount = null;
        try {
            List<JwUserAccount> accountList = jwUserAccountService.find(user.getId(), "1");
            if (!CollectionUtils.isEmpty(accountList)) {
                jwUserAccount = accountList.get(0);
            }
        } catch (Throwable e) {
            e.printStackTrace();
            return ResultVo.error(ResultCode.ERROR, "查询失败");
        }
        return ResultVo.success(jwUserAccount, "查询成功");
    }

    @ApiOperation(notes = "doOcr", httpMethod = "POST", value = "身份证OCR识别")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userToken", value = "用户token", required = true, paramType = "header", dataType = "string"),
            @ApiImplicitParam(name = "imageUrl", value = "图片地址", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "type", value = "识别类型，1身份证，2银行卡", required = true, paramType = "query", dataType = "string"),
    })
    @RequestMapping(value = "doOcr", method = RequestMethod.POST)
    public ResultVo doOcr(String imageUrl, String type, HttpServletRequest request, HttpServletResponse response) {
        if (StringUtils.isEmpty(imageUrl)) {
            return ResultVo.error(ResultCode.ERROR, "请上传要识别的身份证/银行卡图片");
        }
        String userToken = request.getHeader(UserUtils.USER_TOKEN);
        String key = RedisConstant.USER_TOKEN_KEY + userToken;
        User user = (User) RedisUtil.get(key);
        if (user == null) {
            return ResultVo.error(ResultCode.ERROR, "请求头userToken过期");
        }
        try {
            if (RedisUtil.get("realname:ocr:" + type + ":" + user.getId()) == null) {
                RedisUtil.set("realname:ocr:" + type + ":" + user.getId(), 0, 3600 * 24);
            }
            List<FacePayConfig> facePayConfigList = facePayConfigService.find(50, 1, null);
            int count = 4;
            if (facePayConfigList != null && !facePayConfigList.isEmpty()) {
                count = Integer.valueOf(facePayConfigList.get(0).getValue());
            }
            // 每个用户每天只能认证3次
            if (Integer.valueOf(String.valueOf(RedisUtil.get("realname:ocr:" + type + ":" + user.getId()))) >= count) {
                return ResultVo.error(ResultCode.ERROR, "OCR识别次数超过可识别次数，请明天再进行识别");
            }
            // 调用下腾讯云身份证/银行卡OCR识别
            if (type.equals("1")) {
                IDCardOCRResponse idCardOCRResponse = TencentRealnameAuthUtils.idcardOcr(rongyaotuadminDomain, imageUrl);
                RedisUtil.incr("realname:ocr:" + type + ":" + user.getId(), 1);
                return ResultVo.success(idCardOCRResponse, "返回身份证识别结果");
            } else {
                BankCardOCRResponse bankCardOCRResponse = TencentRealnameAuthUtils.bankcardOcr(rongyaotuadminDomain, imageUrl);
                RedisUtil.incr("realname:ocr:" + type + ":" + user.getId(), 1);
                return ResultVo.success(bankCardOCRResponse, "返回银行卡识别结果");
            }
        } catch (Throwable e) {
            e.printStackTrace();
            return ResultVo.error(ResultCode.ERROR, "识别失败");
        }
    }

    // 实名认证
    @ApiOperation(notes = "doRealname", httpMethod = "POST", value = "完善信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userToken", value = "用户token", required = true, paramType = "header", dataType = "string"),
            @ApiImplicitParam(name = "name", value = "姓名", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "idcard", value = "身份证号码", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "bankcard", value = "银行卡号", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "phone", value = "手机号码", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "frontImage", value = "身份证正面", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "backImage", value = "身份证反面", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "subbranch", value = "开户银行支行", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "validDate", value = "身份证有效日期", required = true, paramType = "query", dataType = "string"),
    })
    @RequestMapping(value = "doRealname", method = RequestMethod.POST)
    public ResultVo doRealname(String name, String idcard, String bankcard, String phone, String frontImage, String backImage, String subbranch, String validDate, HttpServletRequest request, HttpServletResponse response) {
        if (StringUtils.isEmpty(frontImage) || StringUtils.isEmpty(backImage)) {
            return ResultVo.error(ResultCode.ERROR, "请上传身份证");
        }
        String userToken = request.getHeader(UserUtils.USER_TOKEN);
        String key = RedisConstant.USER_TOKEN_KEY + userToken;
        User user = (User) RedisUtil.get(key);
        if (user == null) {
            return ResultVo.error(ResultCode.ERROR, "请求头userToken过期");
        }
        JwUserAccount jwUserAccount = new JwUserAccount();
        try {
            // TODO: 这里是否要检查身份证是不是已经有绑定过了
            //System.out.println(RedisUtil.get("11realname:auth:" + user.getId()));
            if (RedisUtil.get("realname:auth:" + user.getId()) == null) {
                RedisUtil.set("realname:auth:" + user.getId(), 0, 3600 * 24);
            }
            // 验证次数改成读取数据库配置，灵活点
            List<FacePayConfig> facePayConfigList = facePayConfigService.find(50, 1, null);
            int count = 4;
            if (facePayConfigList != null && !facePayConfigList.isEmpty()) {
                count = Integer.valueOf(facePayConfigList.get(0).getValue());
            }
            // 每个用户每天只能认证3次
            if (Integer.valueOf(String.valueOf(RedisUtil.get("realname:auth:" + user.getId()))) >= count) {
                return ResultVo.error(ResultCode.ERROR, "银联四要素认证次数超过可认证次数，请明天再进行认证");
            }
            // 调用下腾讯云银联4要素，是否正确才通过
            Boolean verify = TencentRealnameAuthUtils.bankCard4EVerification(name, bankcard, phone, idcard);
            RedisUtil.incr("realname:auth:" + user.getId(), 1);
            if (verify) {
                frontImage = frontImage.replaceAll(".webp", "");
                backImage = backImage.replaceAll(".webp", "");
                String rootPath = "/www/wwwroot/yun.dianbang-st.com/public";
                File frontImageFile = new File(rootPath + frontImage);
                File backImageFile = new File(rootPath + backImage);
                if (!frontImageFile.exists() || !backImageFile.exists()) {
                    return ResultVo.error(ResultCode.ERROR, "不存在该文件");
                }
                jwUserAccount.setName(name);
                jwUserAccount.setIdcard(idcard);
                String nationalImage = "/uploads/idcard/" + jwUserAccount.getName() + '+' + jwUserAccount.getIdcard() + "+national.png";
                String portraitImage = "/uploads/idcard/" + jwUserAccount.getName() + '+' + jwUserAccount.getIdcard() + "+portrait.png";
                FileUtils.copyFile(frontImageFile, new File(rootPath + nationalImage));
                FileUtils.copyFile(backImageFile, new File(rootPath + portraitImage));
                jwUserAccount.setUserId(user.getId());
                jwUserAccount.setBankcard(bankcard);
                jwUserAccount.setPhone(phone);
                jwUserAccount.setFrontImage(nationalImage);
                jwUserAccount.setBackImage(portraitImage);
                if (!StringUtils.isEmpty(subbranch)) {
                    subbranch = subbranch.split("\\(")[0];
                }
                jwUserAccount.setSubbranch(subbranch);
                jwUserAccount.setBankName(subbranch);
                jwUserAccount.setValidDate(validDate);
                jwUserAccount.setStatus(1);
                jwUserAccount.setCreatetime(System.currentTimeMillis() / 1000);
                jwUserAccount.setUpdatetime(System.currentTimeMillis() / 1000);
                jwUserAccountService.insert(jwUserAccount);
            } else {
                return ResultVo.error(ResultCode.ERROR, "银联四要素认证不通过");
            }
        } catch (Throwable e) {
            e.printStackTrace();
            return ResultVo.error(ResultCode.ERROR, "完善失败");
        }
        return ResultVo.success(jwUserAccount, "完善成功");
    }

    @ApiOperation(notes = "doFaceImage", httpMethod = "POST", value = "完善人脸信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userToken", value = "用户token", required = true, paramType = "header", dataType = "string"),
            @ApiImplicitParam(name = "faceImage", value = "人脸图片地址", required = true, paramType = "query", dataType = "string"),
    })
    @RequestMapping(value = "doFaceImage", method = RequestMethod.POST)
    public ResultVo doFaceImage(String faceImage, HttpServletRequest request, HttpServletResponse response) {
        if (StringUtils.isEmpty(faceImage)) {
            return ResultVo.error(ResultCode.ERROR, "人脸图片地址不能为空");
        }
        String userToken = request.getHeader(UserUtils.USER_TOKEN);
        String key = RedisConstant.USER_TOKEN_KEY + userToken;
        User user = (User) RedisUtil.get(key);
        if (user == null) {
            return ResultVo.error(ResultCode.ERROR, "请求头userToken过期");
        }
        JwUserAccount jwUserAccount = null;
        try {
            faceImage = faceImage.replaceAll(".webp", "");
            String rootPath = "/www/wwwroot/yun.dianbang-st.com/public";
            File file = new File(rootPath + faceImage);
            if (!file.exists()) {
                return ResultVo.error(ResultCode.ERROR, "不存在该文件");
            }
            List<JwUserAccount> accountList = jwUserAccountService.find(user.getId(), "1");
            if (!CollectionUtils.isEmpty(accountList)) {
                jwUserAccount = accountList.get(0);
            }
            if (jwUserAccount == null) {
                return ResultVo.error(ResultCode.ERROR, "请先完善信息");
            }
            String nationalImage = "/uploads/face/" + jwUserAccount.getName() + '+' + jwUserAccount.getIdcard() + "+face.png";
            FileUtils.copyFile(new File(rootPath + faceImage), new File(rootPath + nationalImage));
            jwUserAccount.setFaceImage(nationalImage);
            jwUserAccountService.updateFaceImage(jwUserAccount.getId(), jwUserAccount.getFaceImage());
        } catch (Throwable e) {
            e.printStackTrace();
            return ResultVo.error(ResultCode.ERROR, "完善失败");
        }
        return ResultVo.success(jwUserAccount, "完善成功");
    }

    // TODO: 上传图片看放到9006那个服务这样子就在内网了，可以操作到文件系统，另外这些文件也就可以操作了
    //          TODO: 主要是要实现实名认证+身份证OCR

    // TODO: 提现申请+能量舱佣金提现记录

    // TODO：再结合经纬度定位+活体检测判断是否再现场，可以实现美导核验流程
    @ApiOperation(notes = "getLiveCode", httpMethod = "GET", value = "获取数字验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userToken", value = "用户token", required = true, paramType = "header", dataType = "string"),
    })
    @RequestMapping(value = "getLiveCode", method = RequestMethod.GET)
    public ResultVo getLiveCode(HttpServletRequest request, HttpServletResponse response) {
        String userToken = request.getHeader(UserUtils.USER_TOKEN);
        String key = RedisConstant.USER_TOKEN_KEY + userToken;
        User user = (User) RedisUtil.get(key);
        if (user == null) {
            return ResultVo.error(ResultCode.ERROR, "请求头userToken过期");
        }
        String liveCode = "";
        try {
            liveCode = TencentRealnameAuthUtils.getLiveCode();
        } catch (Throwable e) {
            e.printStackTrace();
            return ResultVo.error(ResultCode.ERROR, "查询失败");
        }
        return ResultVo.success(liveCode, "查询成功");
    }

    @ApiOperation(notes = "liveCheck", httpMethod = "GET", value = "活体检测")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userToken", value = "用户token", required = true, paramType = "header", dataType = "string"),
            @ApiImplicitParam(name = "videoUrl", value = "视频文件url", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "liveCode", value = "数字验证码", required = true, paramType = "query", dataType = "string"),
    })
    @RequestMapping(value = "liveCheck", method = RequestMethod.GET)
    public ResultVo liveCheck(String videoUrl, String liveCode, HttpServletRequest request, HttpServletResponse response) {
        String userToken = request.getHeader(UserUtils.USER_TOKEN);
        String key = RedisConstant.USER_TOKEN_KEY + userToken;
        User user = (User) RedisUtil.get(key);
        if (user == null) {
            return ResultVo.error(ResultCode.ERROR, "请求头userToken过期");
        }
        Boolean checkResult = false;
        try {
            if (RedisUtil.get("realname:livecheck:" + user.getId()) == null) {
                RedisUtil.set("realname:livecheck:" + user.getId(), 0, 3600 * 24);
            }
            // 验证次数改成读取数据库配置，灵活点
            List<FacePayConfig> facePayConfigList = facePayConfigService.find(70, 1, null);
            int count = 10;
            if (facePayConfigList != null && !facePayConfigList.isEmpty()) {
                count = Integer.valueOf(facePayConfigList.get(0).getValue());
            }
            // 每个用户每天只能认证3次
            if (Integer.valueOf(String.valueOf(RedisUtil.get("realname:livecheck:" + user.getId()))) >= count) {
                return ResultVo.error(ResultCode.ERROR, "活体检测次数超过可认证次数，请明天再进行认证");
            }
            checkResult = TencentRealnameAuthUtils.liveCheck(TencentRealnameAuthUtils.getBase64Str(videoUrl), liveCode);
            RedisUtil.incr("realname:livecheck:" + user.getId(), 1);
        } catch (Throwable e) {
            e.printStackTrace();
            return ResultVo.error(ResultCode.ERROR, "查询失败");
        }
        return ResultVo.success(checkResult, "查询成功");
    }
}
